<?php
namespace Hive;
use Fox\Dao\SqlFragment;
use DateTime;
use Fox\Common\Address,Hive\Mission\Announce;
/**
 * Company Object.
 *
 * It represant a Company.
 *
 * @author Xavier VILAIN
 * @package hr
 * @subpackage mission
 * @property int 	$missionid			Mission Id
 * @property string $title				Mission title
 * @property string $description		Description
 * @property string $companid			Company Id (@link Company)
 * @property date 	$description 		Description
 * @property string $contract_type		Contract Type
 * @property int 	$adrid				Address Id (can be null)
 * @property bool 	$loekz 				Deletion Flag if true is an been deleted
 */
class Mission extends \Fox\Object\Versioned {
	
	public static $JOIN_ANNOUNCES = array(
		'source' => 'missions',
		'table' => 'missions_announces',
		'short' => 'an',
		'foreign' => 'missionid',
		'column' => 'missionid',
		'type' => 'LEFT JOIN');

	public static $JOIN_PARTNERS = array(
		'source' => 'ressources',
		'table' => 'mission_partners',
		'short' => 'p',
		'foreign' => 'partnerid',
		'column' => 'ressource_id',
		'type' => 'INNER JOIN');
	
	/**
	 *
	 * Enter description here ...
	 * @var unknown_type
	 */
	const BUNDLE_NAME = 'missions';

	/**
	 * 
	 * Document Category Group
	 * @var string
	 */
	const DOC_GROUPING = 'mi';
	
	/**
	 * Changing Documents
	 * @var string
	 */
	const CHANGE_DOCUMENTS = 'documents';
	
	/**
	 * Changing Documents
	 * @var string
	 */
	const CHANGE_DOCUMENT_DELETE = 'rm-document';

	/**
	 * Add/Del Partners in the mission
	 * @var string
	 */
	const CHANGE_PARTNERS = 'partners';

	/**
	 * Add Partner in the mission
	 * @var string
	 */
	const CHANGE_ADD_PARTNER = 'add-partner';
	
	/**
	 * Add Partner in the mission
	 * @var string
	 */
	const CHANGE_PARTNER_REMOVE = 'del-partner';
	
	/**
	 * Metadata Information
	 * @var string
	 */
	const CHANGE_METADATA = 'metadata';
	
	/**
	 * Add/Del Partners in the mission
	 * @var string
	 */
	const STATUS_CLOSED = 'CL';
	
	/**
	 * Open Mission
	 * @var string
	 */
	const STATUS_OPEN = 'OP';
	
	/**
	 * Publish the mission online
	 * @var string
	 */
	const STATUS_PUBLISH = 'PU';

	/**
	 * Task Reference Type equal to Mission
	 * @var int
	 */
	const TASK_REFERENCE = 2;
	
	/**
	 * Link to the announces
	 */
	const LINK_ANNOUNCES = 'announces';
	
	/**
	 * Link to the partners
	 */
	const LINK_PARTNERS = 'partners';
	
	/**
	 * Link to the partners
	 */
	const LINK_CANDIDATES = 'candidates';
		
	/**
	 * Link to the documents
	 * @var string
	 */
	const LINK_DOCUMENTS = 'documents';
	
	/**
	 * Link to mission type
	 * @var string
	 */
	const LINK_TYPE = 'type';
	
	/**
	 * Default Mission Type
	 * @var string
	 */
	const TYPE_DEFAULT = '1';
		
	/**
	 * 
	 * Last Assigned Mission
	 * @var string
	 */
	const LAST_USED = 'mission-last-used';

	/**
	 * Mission Message Reference
	 * @var int
	 */
	const MESSAGE_REFERENCE = 2;
	
	/**
	 * Company Name
	 * @var string
	 */
	private $companyName = null;

	/**
	 * Company Object
	 * @var Company
	 */
	private $company = null;

	/**
	 * Announces
	 * @var array
	 */
	private $announces = null;

	/**
	 * Announces
	 * @var array
	 */
	private $partners = null;

	/**
	 * Store Workflow Object
	 * 
	 * @var \Hive\Workflow
	 */
	private $_workflow = null;
	
	/**
	 * List of Mission Candidates
	 * 
	 * @var string
	 */
	private $_candidates = null;
		
	/**
	 * List of Mission Contacts (Removing Candidates)
	 * 
	 * @var string
	 */
	private $_contacts = null;
	
	/**
	 * Track if index need to be rebuild
	 * @var bool
	 */
	protected $updateIndex = false;
	
	/**
	 *
	 * @param array $fields
	 */
	protected function afterSetFields(array $fields)
	{
		foreach($this->getProtectedFields() as $fieldName => $value)
		{
			unset($fields[$fieldName]);
		}
		$this->address()->setFields($fields);
		$this->companyName();
	}

	/**
	 * Convert company id into company name
	 * @return string Company Name
	 */
	public function companyName()
	{
		if(empty($this->companyName))
		{
			$this->companyName = $this->company()->name();
		}
		return $this->companyName;
	}

	/**
	 * Find the attached company Object
	 * @return Company
	 */
	public function company()
	{
		if(empty($this->company))
		{
			try {
				$this->company = \Fox\Dao::load(Company::className(),$this->companid);
			}
			catch (\Fox\Object\Exception\NotExist $e) {
				$this->company = new Company();
			}
		}
		return $this->company;
	}

	/**
	 * Retrieve all ressource (including Address,Experience)
	 * @return array
	 */
	public function getData()
	{
		$data = parent::getData();
		$data['companyName'] = $this->companyName();
		return array_merge($this->address()->getData(),
							$data);
	}

	/**
	 * Use for the Search Engine
	 * @return string All object attributes has a string
	 */
	public function content()
	{
		$data = array_merge($this->address()->getNonProtectedData(),
							$this->getNonProtectedData());
		$data['country'] = empty($data['country']) ? null : \Fox\Ddic\DataElement\Text::label('country',$data['country']);
		$data['scholar'] = empty($data['scholar']) ? null : \Fox\Ddic\DataElement\Text::label('scholar',$data['scholar']);
		$data['contract_type'] = empty($data['contract_type']) ? null : \Fox\Ddic\DataElement\Text::label('contract_type',$data['contract_type']);
		$data['companyName'] = $this->companyName();
		return implode(',',$data);
	}

	/**
	 * (non-PHPdoc)
	 * @see includes/classes/Fox/Object/Versioned::beforeVersionUpdate()
	 */
	protected function beforeVersionCreate() {
		// Build Address Link
		$this->address()->create();
		$this->adrid = $this->address()->getId();
	}

	/**
	 * (non-PHPdoc)
	 * @see includes/classes/Fox/Object/Versioned::afterVersionCreate()
	 */
	protected function afterVersionCreate(\Fox\Version $version)
	{
		// Add to the search engine
		$searchEngine = new \Fox\SearchEngine();
		$searchEngine->add($this,$this->getId(),self::className());
	}

	/**
	 * (non-PHPdoc)
	 * @see includes/classes/Fox/Object/Versioned::afterVersionUpdate()
	 */
	protected function afterVersionUpdate()
	{
		$this->updateIndex = false;
		if($this->isChangeType(self::CHANGE_DEFAULT)) {
			$this->updateIndex = true;
		}
		$_SESSION[self::LAST_USED] = $this->getId();
	}

	/**
	 * (non-PHPdoc)
	 * @see Fox.Object::afterUpdateCommit()
	 */
	protected function afterUpdateCommit() {
		if($this->updateIndex) {
			$this->updateIndex = false;
			$inLineId = $this->getId();
			$title = utf8_encode(\Msg(\Fox\Msg::BUNDLE,\Fox\Msg::MSG_UPDATE,$this->label()));
			$status = new \Fox\Background\JsonStatusReporter(
					$title,
					array(
						'Starting Indexation',
						'Indexation Complete',
					)
				);
			$obj = $this;
			$grouping_type = self::classname();
			\Fox\Background\Task::run($status, function ($status) use ($obj,$inLineId,$grouping_type)  {
				$status->start();
				$searchEngine = new \Fox\SearchEngine();
				$searchEngine->synchronize($obj,$inLineId,$grouping_type,$status);
				$status->success();
			});
		}
	}
	
	/**
	 * (non-PHPdoc)
	 * @see includes/classes/Fox/Object/Versioned::beforeVersionUpdate()
	 */
	protected function beforeVersionUpdate($changed) {
		// Check if address entry has changed
		if($this->address()->changed() || !$this->address()->exists())
		{
			if($this->address()->exists())
			{
				$this->address()->prepareUpdate(Ressource::CHANGE_DEFAULT);
				$this->address()->update();
			}
			else
			{
				$this->address()->create();
				$this->adrid = $this->address()->getId();
			}
			$changed = true;
		}
		return $changed;
	}
	/**
	 * (non-PHPdoc)
	 * @see Fox\Object\Versioned::delete()
	 */
	public function delete()
	{
		$handle = \Fox\Dao::infos(self::className())->handle();
		$handle->beginTransaction();
		// Remove All Search Help matches
		$searchEngine = new \Fox\SearchEngine();
		$searchEngine->deleteMatchesByGrouping($this);
		parent::delete();
		$handle->commit();
	}

	/**
	 * Load Ressource Address
	 * @return Address
	 */
	public function address()
	{
		if(empty($this->address))
		{
			$finder = new Address();
			$addresses =  $finder->find(new \Fox\Dao\SqlFragment('adrid = ?',array($this->adrid)));
			if(count($addresses) > 0)
			{
				$this->address = $addresses[0];
			}
			else
			{
				$this->address = $finder;
			}
		}
		return $this->address;
	}

	/**
	 * @return string Ressource language
	 */
	public function language()	{
		return 'fr';//@FIXME add language in the field list
	}

	/**
	 *
	 * Add a new announce to the mission
	 * @return array of Announce
	 */
	public function tags()
	{
		return $this->tags;
	}

	/**
	 * Set/Get a partner link
	 * @deprecated
	 * @return array
	 */
	public function partner($partnerid,$role = null)
	{
		if(empty($this->partners))
		{
			$this->partners();
		}
		if(isset($this->partners[$partnerid]))
		{
			if(!empty($role))
				$this->partners[$partnerid]->setFields(array('role' => $role));
		}
		else
		{
			$partner = new Mission\Partner();
			$today = new DateTime();
			$partner->setFields(array(	'role' => $role,
										'partnerid' => $partnerid,
										'missionid' => $this->getId(),
										'status' => Mission\Partner::STATUS_DEFAULT,
										'defaultflag' => 0,
										'cdate' => $today->format('Y-m-d H:i:s')
									)
								);
			$this->partners[$partnerid] = $partner;
		}
		return $this->partners[$partnerid];
	}

	/**
	 * Load all customer partners (as customer objects)
	 * @return array
	 */
	public function partnersSourceObjects($fragments = null)
	{
		$fragments[] = new \Fox\Dao\SqlFragment('p.missionid = ?',array($this->getId()));
		$finder = new Ressource();
		return $finder->find(\Fox\Dao\SqlFragment::combine($fragments),null,array(self::$JOIN_PARTNERS));
	}

	/**
	 *
	 * Find partner link
	 * @param int $id	Partner Id
	 * @return Mission\Partner
	 */
	public function partnerLink($id)
	{
		$finder = new Mission\Partner();
		$partners = $finder->find(new \Fox\Dao\SqlFragment('missionid = ? and partnerid = ?',
							array($this->getId(),$id)));
		if(count($partners) > 0)
		{
			return $partners[0];
		}
		return false;
	}

	/**
	 * Find all associated tasks
	 * @return array
	 */
	public function tasks($displayDelete = false)
	{
		if(empty($this->tasks))
		{
			$finder = \Fox\Dao::finder(\Shama\Task::className())
							->orderBy('duedate','DESC');
			if(!$displayDelete)	{
				$finder->where('status != ?',array(\Shama\Task::STATUS_CLOSED));
			}			
							
			$finder->follow(\Shama\Task::LINK_REFERENCES)
								->where('reference = ? AND reference_id= ?',
									array(self::TASK_REFERENCE,$this->getId()));					
			$this->tasks = $finder->find();
		}
		return $this->tasks;
	}
	
	/**
	 * Load all documents 
	 */
	public function allDocuments()
	{
		foreach($this->documents() as $documentLink)
		{
			$documentIds[] = $documentLink->docid;
		}
		if(!empty($documentIds))
		{
			$finder = new \Fox\Document();
			$res = $finder->find(new \Fox\Dao\SqlFragment('docid IN (?)',
							array($documentIds),
							array(\Doctrine\DBAL\Connection::PARAM_STR_ARRAY)));
			return $res;
		}
		return null;
	}
	
	/**
	 * Find and return mission worflow
	 * 
	 * @return \Hive\Workflow
	 */
	public function workflow() {
		if(empty($this->_workflow)) {
			$this->_workflow = $this->type()->workflow();
		}
		return $this->_workflow;
	}
	
	/**
	 * Find accros partners which ones are candidates 
	 * according to their role
	 * 
	 * @return array of Mission\Partner
	 */
	public function candidates() {
		if(empty($this->_candidates)) {
			$this->_candidates = array();
			foreach($this->partners() as $partner) {
				if($partner->role == Mission\Partner::ROLE_CANDIDATE) {
					$this->_candidates[$partner->partnerid] = $partner;
				}
			}
		}
		return $this->_candidates;
	}
	
	/**
	 * Find accros partners which ones are candidates 
	 * according to their role
	 * 
	 * @return array of Mission\Partner
	 */
	public function contacts() {
		if(empty($this->_contacts)) {
			$this->_contacts = array();
			foreach($this->partners() as $partner) {
				if($partner->role != Mission\Partner::ROLE_CANDIDATE && 
					$partner->role != Mission\Partner::ROLE_ACCOUNT
					 ) {
					$this->_contacts[$partner->partnerid] = $partner;
				}
			}
		}
		return $this->_contacts;
	}

	/**
	 * Single Query to load all needed contact information
	 * 
	 */
	public function contactsInfos($fragments = null) {
		
		$addressPro = \Hive\Ressource::ADDRESS_PRO;
		//$addressPerso  = \Hive\Ressource::ADDRESS_PERSO;
		$infos = \Fox\Dao::infos(self::className());
		$query = $infos->handle()->createQueryBuilder();
		$query->select('c.missionid','c.partnerid','c.role','t.last_name','t.first_name','t.email'
				,'aperso.phone1 as perso_phone1','aperso.phone2 as perso_phone2'
				,'apro.email1 as pro_email','apro.phone1 as pro_phone1','apro.phone2 as pro_phone2'
				)
			->from('mission_partners','c')
			->innerJoin('c','ressources','t','t.ressource_id = c.partnerid')
			->innerJoin('c','address','aperso','t.adrid = aperso.adrid')
			->leftJoin('c','ressource_addresses','ra','t.ressource_id = ra.ressource_id AND ra.type = '.$addressPro)
			->leftJoin('c','address','apro','ra.adrid = apro.adrid');
			
		$fragments[] = new SqlFragment('missionid = ? ',array($this->getId()));
		$fragment = SqlFragment::combine($fragments);
		$result = $fragment->pushIn($query)->execute()->fetchAll(\PDO::FETCH_ASSOC);
		return $result;
	}
	
	/**
	 * Short Cut to Mission label
	 * @return string
	 */
	public function label() {
		return $this->reference;
	}
	
	/**
	 * 
	 * Find Mission Reference Value 
	 * @param int $id
	 * @return string
	 */
	public static function reference($id) {
		$infos = \Fox\Dao::infos(self::className());
		$query = $infos->handle()->createQueryBuilder();
		$query->select('reference')
				->from($infos->tableName(),'t');
		$fragment = new SqlFragment('missionid = ? ',array($id));	
		return $fragment->pushIn($query)->execute()->fetchColumn();	
	}
	
	/**
	 * 
	 * Count the number of messages
	 * @param unknown_type $id
	 */
	public static function countMessages($id) {
		
		$infos = \Fox\Dao::infos(self::className());
		$query = $infos->handle()->createQueryBuilder();
		$query->select('COUNT(l.messageid)')
				->from('message_labels','l')
				->innerJoin('l','messages','m','m.messageid = l.messageid');
				
		$fragment = new SqlFragment('l.reference = ? AND l.reference_class_id = ? AND m.loekz = ? AND ( m.status = ? OR m.status = ? OR m.status = ? ) ',
									array($id,self::MESSAGE_REFERENCE,0,
										\Orx\Mailer\MailBox\Message::STATUS_READ,
										\Orx\Mailer\MailBox\Message::STATUS_UNREAD,
										\Orx\Mailer\MailBox\Message::STATUS_ARCHIVED));	
		return $fragment->pushIn($query)->execute()->fetchColumn();	
	}
	
	/**
	 * 
	 * Enter description here ...
	 */
	public function countBySteps() {
		$infos = \Fox\Dao::infos(self::className());
		$query = $infos->handle()->createQueryBuilder();
		$query->select('status,COUNT(*) as nb')
				->from('mission_partners','m')
				->groupBy('status');
		
		$fragment = new SqlFragment('missionid = ?',array($this->missionid));	
		return $fragment->pushIn($query)->execute()->fetchAll(\PDO::FETCH_GROUP);	
	}
}
\Fox\Dao::infos(
	Mission::className(),
	new \Fox\Object\Info('missions', \Fox\Databases::DB_APP)
);

// Link To Partners
\Fox\Object\Links::add(\Fox\Dao::link(Mission\Partner::className(), Mission\Partner::LINK_MISSION)
	->to(Mission::className(), Mission::LINK_PARTNERS)
	->on('missionid')
	->versionFrom()
);
// Link To Affected Candidate
\Fox\Object\Links::add(\Fox\Dao::link(Mission\Partner::className(), Mission\Partner::LINK_CANDIDATE_MISSION)
	->to(Mission::className(), Mission::LINK_CANDIDATES)
	->on('missionid')
	->where('role = ?',array(Mission\Partner::ROLE_CANDIDATE))
);
// Link To Announces
\Fox\Object\Links::add(\Fox\Dao::link(Mission\Announce::className(), Mission\Announce::LINK_MISSION)
	->to(Mission::className(), Mission::LINK_ANNOUNCES)
	->on('missionid')
	->versionFrom());

// Link To Documents (Order, Contract...)
\Fox\Object\Links::add(\Fox\Dao::link(Mission\Document::className(),Mission\Document::LINK_MISSION)
	->to(Mission::className(), Mission::LINK_DOCUMENTS)
	->on('missionid')
	->versionFrom()
);

// Link to Types
\Fox\Object\Links::add(\Fox\Dao::link(Mission::className(),Mission::LINK_TYPE)
	->to(Mission\Type::className(),Mission\Type::LINK_MISSIONS)
	->on('type')
	->oneToOne()
	->linkOnly()
);